using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using NetCoreServer;

namespace Cavy.UdpClient.SystemUdpClient
{
    public class TransportNetCoreServerServer : Transport
    {
        private EchoUdpServer _udpServer;
        private Dictionary<string, Dictionary<int, EndPoint>> _endpoints =
            new Dictionary<string, Dictionary<int, EndPoint>>();

        public override int Bind(int port = 0)
        {
            _udpServer = new EchoUdpServer(IPAddress.Any, port);
            _udpServer.Start();
            return port;
        }

        public override void Connect(string address, int port)
        {
            
        }

        public override bool EnableBroadcast { get; set; }

        public override int ReceiveBufferSize
        {
            get => _udpServer.OptionReceiveBufferSize;
            set => _udpServer.OptionReceiveBufferSize = value;
        }
        public override void Close()
        {
            
        }

        public override void Dispose()
        {
            _udpServer.Dispose();
            IsReceiving = false;
        }

        public override void ReceiveAsync()
        {
            if(IsReceiving)return;
            IsReceiving = true;
            _udpServer.Start();
            _udpServer.OnReceivedEvent += (point, bytes, arg3, arg4) =>
            {
                CallOnReceived(new UdpResult()
                {
                    Buffer = bytes,
                    RemoteEndPoint = new IpEndPoint()
                    {
                        Address = ((IPEndPoint)point).Address.ToString(),
                        Port = ((IPEndPoint)point).Port
                    }
                });
            };
        }

        public override void Send(byte[] data, int dataLength, string host, int port)
        {
            if (!_endpoints.TryGetValue(host, out var address))
            {
                _endpoints[host] = address = new Dictionary<int, EndPoint>();
                
            }
            if (!address.TryGetValue(port, out var endPoint))
            {
                endPoint = new IPEndPoint(IPAddress.Parse(host), port);
                address[port] = endPoint;
            }
            _udpServer.Send(endPoint, data);
        }
    }
    
    class EchoUdpServer : UdpServer
    {
        public bool Started { get; set; }
        public bool Stopped { get; set; }
        public bool Errors { get; set; }

        public EchoUdpServer(IPAddress address, int port) : base(address, port) {}
        public event System.Action<EndPoint, byte[], long, long> OnReceivedEvent;
        public event System.Action<EndPoint, long> OnSentEvent;

        protected override void OnStarted()
        {
            Started = true; 
            ReceiveAsync();
        }
        protected override void OnStopped() { Stopped = true; }

        protected override void OnReceived(EndPoint endpoint, byte[] buffer, long offset, long size)
        {
            OnReceivedEvent?.Invoke(endpoint, buffer, offset, size);
            ReceiveAsync();
        }

        protected override void OnSent(EndPoint endpoint, long sent)
        {
            OnSentEvent?.Invoke(endpoint, sent);
        }

        protected override void OnError(SocketError error)
        {
            Errors = true;
        }
    }
}